﻿namespace ScrumLite.Services
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Transactions;
    using System.Linq;
    using Contracts;

    public class LinqDeliverablesService : IDeliverablesService
    {
        ScrumLite.Data.IDeliverableStore store;

        public LinqDeliverablesService(ScrumLite.Data.IDeliverableStore store)
        {
            this.store = store;
        }

        public LinqDeliverablesService()
            : this(new ScrumLite.Data.DeliverableStore())
        { }


        public Deliverable[] GetDeliverables(string projectId)
        {
            ScrumLite.Data.Deliverable[] deliverables = this.store.GetDeliverables(projectId);                  

            List<Deliverable> deliverablesModel = new List<Deliverable>();
            foreach (ScrumLite.Data.Deliverable item in deliverables)
            {                
                Deliverable result = new Deliverable();
                result.Id = item.id;
                result.Moniker = item.moniker;
                result.Name = item.fileName;
                result.ReleasedOn = item.releasedOn;
                result.Url = new Uri(item.uri_repository);

                // call workareas by Deliverable.
                ScrumLite.Data.WorkArea[] linqDataWorkAreas = this.store.GetWorkAreas(item.id);
                
                // Call if is defective
                result.IsDefective = this.store.IsDefect(item.id);

                // Map 
                List<WorkArea> workAreasModel = new List<WorkArea>();
                
                if (linqDataWorkAreas != null)
                {
                    foreach (ScrumLite.Data.WorkArea itemWorkArea in linqDataWorkAreas)
                    {
                        workAreasModel.Add(new WorkArea() { Id = itemWorkArea.id.ToString(), Name = itemWorkArea.name });
                    }
                }
                result.WorkAreas = workAreasModel.ToArray();

                deliverablesModel.Add(result);
            }

            return deliverablesModel.ToArray();

        }

        public Deliverable GetDeliverable(string id)
        {
            ScrumLite.Data.Deliverable deliverable = this.store.GetDeliverable(new Guid(id));

            if (deliverable == null)
            {
                return null;
            }

            Deliverable result = new Deliverable()
            {
                Id = deliverable.id,
                Moniker = deliverable.moniker,
                Name = deliverable.fileName,
                ReleasedOn = deliverable.releasedOn,
                Url = new Uri(deliverable.uri_repository)
            };

            return result;
        }

        public Guid GetDeliverableByMoniker(string projectId, int moniker)
        {
            return this.store.GetDeliverableByMoniker(projectId, moniker);
        }

        public Deliverable[] GetDeliverablesByWorkArea(WorkArea workArea)
        {
            if (workArea == null)
            {
                return null;
            }

            // map to Data.WorkArea
            ScrumLite.Data.WorkArea area = new ScrumLite.Data.WorkArea() { id = new Guid(workArea.Id), name = workArea.Name };

            // get deliverables 
            ScrumLite.Data.Deliverable[] deliverables = store.GetDeliverablesByWorkArea(area);

            List<Deliverable> deliverablesModel = new List<Deliverable>();

            foreach (ScrumLite.Data.Deliverable item in deliverables)
            {
                Deliverable result = new Deliverable();
                result.Id = item.id;
                result.Moniker = item.moniker;
                result.Name = item.fileName;
                result.ReleasedOn = item.releasedOn;
                result.Url = new Uri(item.uri_repository);

                var workAreas = (from wa in item.DeliverableWorkAreas
                                 select new ScrumLite.Services.Contracts.WorkArea { Id = wa.pk_workarea.ToString(), Name = wa.WorkArea.name }).ToArray();

                result.WorkAreas = workAreas;

                deliverablesModel.Add(result);
            }

            return deliverablesModel.ToArray();
        }

        public WorkArea[] GetWorkAreas(string deliverableId)
        {
            List<WorkArea> areas = (from wa in this.store.GetWorkAreas(new Guid(deliverableId))
                                    select new WorkArea { Id = wa.id.ToString(), Name = wa.name }).ToList();

            return areas.ToArray();
        }

        public void Add(string projectId, Deliverable deliverable)
        {
            if (string.IsNullOrEmpty(projectId))
            {
                throw new ArgumentNullException("projectId");
            }

            using (TransactionScope scope = new TransactionScope())
            {
                ScrumLite.Data.Deliverable data = Map(deliverable);

                data.id = Guid.NewGuid();
                data.moniker = GetNextMoniker(projectId);
                data.pk_project = new Guid(projectId);
                this.store.Add(data);
                scope.Complete();
            }
        }

        public void Update(string projectId, Deliverable deliverable)
        {
            if (string.IsNullOrEmpty(projectId))
            {
                throw new ArgumentNullException("projectId");
            }

            using (TransactionScope scope = new TransactionScope())
            {
                ScrumLite.Data.Deliverable data = Map(deliverable);

                data.pk_project = new Guid(projectId);
                this.store.Update(data);
                scope.Complete();
            }
        }

        public int GetNextMoniker(string projectId)
        {
            int maxMoniker = this.store.RetrieveLastMoniker(projectId);
            return ++maxMoniker;

        }


        private static ScrumLite.Data.Deliverable Map(Deliverable modelDeliverable)
        {
            if (modelDeliverable == null)
                return null;

            ScrumLite.Data.Deliverable result = new ScrumLite.Data.Deliverable();
            result.id = modelDeliverable.Id;
            result.moniker = modelDeliverable.Moniker;
            result.fileName = modelDeliverable.Name;
            result.releasedOn = modelDeliverable.ReleasedOn;
            result.uri_repository = modelDeliverable.Url.ToString();

            result.DeliverableWorkAreas = new System.Data.Linq.EntitySet<ScrumLite.Data.DeliverableWorkArea>();
            foreach (WorkArea item in modelDeliverable.WorkAreas)
            {
                result.DeliverableWorkAreas.Add(new ScrumLite.Data.DeliverableWorkArea() { id = Guid.NewGuid(), pk_workarea = new Guid(item.Id), pk_deliverable = modelDeliverable.Id });
            }

            return result;
        }
         
    }
}
